#include "../header/Server.h"

int Server::id = -1;

ThreadPool *Server::pool = nullptr;

bool Server::isCompleteShunt = false;

pthread_mutex_t Server::mutex = PTHREAD_MUTEX_INITIALIZER;

Server::~Server() {
    endServer();
    pthread_mutex_destroy(&mutex);
}

void Server::startServer() {
    if (!NetworkTools::isServerPortUse()) {
        pthread_mutex_lock(&mutex);
        if (!NetworkTools::isServerPortUse()) {
            printf("Start Server!\n");
            pool = new ThreadPool(60, 3, 8, new queue<Task>(), new SimpleThreadFactory());
            pool->submitTask(pool, Server::serverWorkThread);
        }
        pthread_mutex_unlock(&mutex);

    } else {
        printf("The Port Is Occupied!\n");
        getchar();
        system("pause");
        pthread_exit(nullptr);
    }
}

void Server::endServer() {
    if (!isCompleteShunt) {
        pthread_mutex_lock(&mutex);
        if (NetworkTools::isServerPortUse()) {
            delete pool;
            isCompleteShunt = true;
        }
        pthread_mutex_unlock(&mutex);
    }
}

void Server::serverWorkThread(void *args) {
    // 1.获取线程池对象指针
    ThreadPool *pool = static_cast<ThreadPool *>(args);

    // 2.创建监听的套接字
    int server_fd = -1;
    pool->server_fd = server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (server_fd == -1) {
        printf("Server Create Socket Fail!\n");
        pthread_exit(nullptr);
    }
    printf("Server Create Socket Success!\n");


    // 3.绑定本地的 IP 和 PORT
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(SERVER_PORT);
    server_address.sin_addr.s_addr = INADDR_ANY;
    int ret = bind(server_fd, (struct sockaddr *) &server_address, sizeof(server_address));
    if (ret == -1) {
        close(server_fd);
        printf("Server IP And PORT Bind Fail!\n");
        pthread_exit(nullptr);
    }
    printf("Server Bind Local 6000 Port Success!\n");

    // 4.设置监听
    ret = listen(server_fd, 128);
    if (ret == -1) {
        close(server_fd);
        printf("Server Listen Local Connect Fail!\n");
        pthread_exit(nullptr);
    }
    printf("Server Listen Local Connect Success!\n");

    // 5.将等待客户端连接的任务提交到线程池中
    pair<ThreadPool *, int> *thread_pool_pointer_and_server_pid = new pair<ThreadPool *, int>(pool, server_fd);
    pool->submitTask(thread_pool_pointer_and_server_pid, Server::serverAcceptTaskThread);
    pthread_exit(nullptr);
}

void Server::serverAcceptTaskThread(void *args) {
    // 1.获取线程池对象指针和服务端文件描述符
    pair<ThreadPool *, int> thread_pool_pointer_and_server_pid = *static_cast<pair<ThreadPool *, int> *>(args);
    ThreadPool *pool = thread_pool_pointer_and_server_pid.first;
    int server_fd = thread_pool_pointer_and_server_pid.second;

    while (true) {
        // 2.阻塞并等待客户端连接
        struct sockaddr_in client_address;
        socklen_t client_sock_length = sizeof(client_address);
        int client_fd = accept(server_fd, (struct sockaddr *) &client_address, &client_sock_length);
        if (client_fd == -1) {
            close(server_fd);
            printf("Server Accept Client Connect Fail!\n");
            pthread_exit(nullptr);
        }
        printf("Server Accept Client Connect Success!\n");

        // 3.与客户端建立连接成功, 打印客户端的 IP 和 PID
        char client_ip[32];
        printf("Client IP: %s, Client PID: %d",
               inet_ntop(AF_INET, &client_address.sin_addr, client_ip, sizeof(client_ip)),
               ntohs(client_address.sin_port));

        // 4.将与客户端通信的任务提交到线程池中
        pair<int, struct sockaddr_in> *client_fd_and_client_address = new pair<int, struct sockaddr_in>(client_fd,
                                                                                                        client_address);
        pool->submitTask(client_fd_and_client_address, Server::serverCommunicateTaskThread);
    }
}

void Server::serverCommunicateTaskThread(void *args) {
    // 1.获取客户端文件描述符和客户端 IP 地址相关的信息
    pair<int, struct sockaddr_in> client_fd_and_client_address = *static_cast< pair<int, struct sockaddr_in> *>(args);
    int client_fd = client_fd_and_client_address.first;
    struct sockaddr_in client_address = client_fd_and_client_address.second;

    // 2.与客户端通信
    while (true) {
        char buffer[1024];
        int length = recv(client_fd, buffer, sizeof(buffer), 0);

        if (0 < length) {
            string public_key = buffer;
            send(client_fd, buffer, length, 0);

            printf("public_key = %s\n", buffer);
            string message = NetworkTools::decryptionMessage(public_key);

            if (!message.empty()) {
                printf("Public Key Verify Success!\n");
                printf("Client(%d) Say: %s\n", client_address.sin_port, message.c_str());
            } else {
                printf("Public Key Verify Fail!\n");
            }

        } else if (0 == length) {
            printf("The Client Is Disconnect!\n");
            break;

        } else {
            close(client_fd);
            printf("Receive Server Data Fail!\n");
            pthread_exit(nullptr);
        }
    }

    // 4.关闭客户端文件描述符
    close(client_fd);
}